package network.TCP;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

import model.data.FileDescription;

/**
 * Project ChatSystemG6 - INSA 4INFOA1 - 2013/2014
 * <P>
 * <li>ClientTCP create a client in charge of the file transmission</li>
 * 
 * @author Christelle SIAGO HAPPI
 * 
 */

public class ClientTCP extends Thread implements Runnable {

	/**
	 * The listening socket of the the client
	 */
	private Socket socket;

	/**
	 * input file stream to read
	 */
	private BufferedReader input;

	/**
	 * output file stream to read
	 */
	private BufferedWriter output;

	/**
	 * the description file to send
	 */
	private FileDescription fileToSend;

	/**
	 * the port of the server
	 */
	private short serverPort;

	/**
	 * the IP address of the server
	 */
	private InetAddress serverAddress;

	/**
	 * the progress bar of the transmission file
	 */
	private ProgressBar progressBar;

	/**
	 * 
	 * @param serverAddress
	 *            : TheIP address of the server
	 * @param serverPort
	 *            : the listening port of the client
	 * @param file
	 *            : the file to be sent
	 */

	public ClientTCP(InetAddress serverAddress, short serverPort,
			FileDescription file) {
		this.setServerAddress(serverAddress);
		this.setServerPort(serverPort);
		this.setFile(file);
		progressBar = new ProgressBar(file.getFile().length(), 'e');
	}

	/**
	 * 
	 * @param serverAddress
	 *            : : TheIP address of the server
	 * @param serverPort
	 *            : the listening port of the client
	 * @param file
	 *            : the file to be sent
	 * @throws UnknownHostException
	 */
	public ClientTCP(String serverAddress, short serverPort,
			FileDescription file) throws UnknownHostException {
		this(InetAddress.getByName(serverAddress), serverPort, file);

	}

	/**
	 * assign a port number to the server
	 * 
	 * @param port
	 */

	public final void setServerPort(short port) {
		if (port > 1024)
			serverPort = port;
	}

	/**
	 * assign an IP address to the server
	 * 
	 * @param address
	 */
	public final void setServerAddress(InetAddress address) {
		this.serverAddress = address;
	}

	/**
	 * assign the file to send
	 * 
	 * @param file
	 */
	public final void setFile(FileDescription file) {
		this.fileToSend = new FileDescription(file);
	}

	/**
	 * launch the client
	 */

	public void startClient() {

		// Step 2: wait for a connection
		try {
			ClientTCP.sleep(1000);
			connect();
		} catch (InterruptedException ex) {
			Logger.getLogger(ClientTCP.class.getName()).log(Level.SEVERE, null,
					ex);
		} catch (IOException ex) {
			Logger.getLogger(ClientTCP.class.getName()).log(Level.SEVERE, null,
					ex);
		}

		// Step 3: Recuperation flow connection
		System.out
				.println("Successfully connected to server port  : " + socket);
		try {
			openFlux();
		} catch (IOException ex) {
			Logger.getLogger(ClientTCP.class.getName()).log(Level.SEVERE, null,
					ex);
		}

		// Step 4: Treat the connection.
		try {
			sendData();
		} catch (IOException ex) {
			Logger.getLogger(ClientTCP.class.getName()).log(Level.SEVERE, null,
					ex);
		}

		// Step 5: Close the stream
		closeFlux();

	}

	/**
	 * Connection to the server
	 * 
	 * @throws IOException
	 * 
	 */
	private void connect() throws IOException {
		try {
			System.out.println("Connection attempt .... :" + serverAddress
					+ "to the port" + serverPort + "\n");
			socket = new Socket(serverAddress, serverPort);
			System.out.println("Creation client socket succeeded");

		} catch (java.io.IOException ex) {
			Logger.getLogger(ClientTCP.class.getName()).log(Level.SEVERE, null,
					ex);
			socket.close();
		}

	}

	/**
	 * opening input and output flow
	 * 
	 * @throws IOException
	 */
	private void openFlux() throws IOException {
		try {
			// getting flow
			output = new BufferedWriter(new OutputStreamWriter(
					socket.getOutputStream()));
		} catch (java.io.IOException ex) {
			Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null,
					ex);
			output.close();
		}
	}

	/**
	 * Sending data
	 */
	private void sendData() throws IOException {

		Speed TransferSpeed = new Speed();

		boolean transfer = true;

		char[] lineRead;
		int octetRead = 0;
		int octectTreaty = 0;

		int size = (int) fileToSend.getFile().length();

		FileReader reader = new FileReader(fileToSend.getFile());
		input = new BufferedReader(reader);

		long startTime = new Date().getTime();

		// While we're not at the end of file
		while (transfer) {
			lineRead = new char[size];
			octetRead = input.read(lineRead, 0, lineRead.length);
			if (octetRead > 0) // If the table is not empty in sending data
			{
				System.out.println("the client wrote: " + lineRead.toString());
				output.write(lineRead);
				output.flush();
			}
			octectTreaty = octectTreaty + octetRead;

			// Calculate the transfer speed
			TransferSpeed.getSpeed(startTime, octectTreaty);
			progressBar.setProgressBar(TransferSpeed);

			if (octectTreaty == size) {
				transfer = false;
			}

		}
		try {
			ClientTCP.sleep(1000);
		} catch (InterruptedException ex) {
			Logger.getLogger(ClientTCP.class.getName()).log(Level.SEVERE, null,
					ex);
		}

	}

	/**
	 * Close Flow
	 */
	private void closeFlux() {

		try {

			if (input != null)
				input.close();
			if (output != null)
				output.close(); // close output flow
			if (socket != null)
				socket.close(); // close the socket
		} catch (java.io.IOException ex) {
			Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null,
					ex);
		}

	}

	@Override
	public void run() {
		startClient();
	}

}
